﻿using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.Portal.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web.UI.HtmlControls;

namespace Com.FastSearch.SharePoint.WebControls.ESPSearchWebParts.UI
{
    public class ESPAutoCompleteSearchBox : SearchBoxEx
    {
        #region Constants

        // Used for the embedded autocomplete script
        private const string AutoCompleteIncludeScriptKey = "autoCompleteIncludeScript";
        private const string IncludeScriptFormat = @"<script language=""{0}"" src=""{1}{2}""></script>";

        #endregion

        #region Private Variables

        private string javaScriptFiles = "qs.js,bl.js";
        private string autoCompleteEmbeddedScriptFormat = "<script type=\"text/javascript\">\n" +
                   "function initQuerySuggester () {\n" +
                    "var sqs = new QuerySuggester();\n" +
                    "sqs.initialize(\"{PROXY}\", \"{FORM_ID}\", \"{AUTOCOMPLETE_DIV_CLIENT_ID}\", \"{INPUTBOX_ID}\");\n" +
                   "}\n" +
                   "if (document.addEventListener) { document.addEventListener(\"DOMContentLoaded\", initQuerySuggester, false); }\n" +
                   "else if(document.attachEvent) { document.attachEvent(\"onreadystatechange\", initQuerySuggester);}\n" +
                "</script>\n";

        private string autoCompleteWebProxyPage = "/_layouts/autocompleteproxy/autocompleteproxy.aspx?q=";
        private string autocompleteScriptDirLocation = "/_layouts/autocompleteproxy/";

        #endregion

        #region Configurable Parameters

        [Browsable(true),
         Category("Auto Complete Configuration"),
         WebPartStorage(Storage.Shared),
         FriendlyName("JavaScript files"),
         Description("The name of the file holding the javascript code that will be included to the page. Multiple files can be added by separating them with a comma \",\".")]
        public string JavaScriptFiles
        {
            get { return javaScriptFiles; }
            set { javaScriptFiles = value; }
        }

        [Category("Auto Complete Configuration"),
         WebPartStorage(Storage.Shared),
         Browsable(true),
         FriendlyName("Embdded Startup Script Format"),
         Description("TODO")]
        public string AutoCompleteEmbeddedScriptFormat
        {
            get { return autoCompleteEmbeddedScriptFormat; }
            set { autoCompleteEmbeddedScriptFormat = value; }
        }

        [Category("Auto Complete Configuration"),
         WebPartStorage(Storage.Shared),
         Browsable(true),
         FriendlyName("Directory where the javascript files are located."),
         Description("TODO")]
        public string AutocompleteScriptDirLocation
        {
            get { return autocompleteScriptDirLocation; }
            set { autocompleteScriptDirLocation = value; }
        }

        [Category("Auto Complete Configuration"),
         WebPartStorage(Storage.Shared),
         Browsable(true),
         FriendlyName("Auto Complete Web Proxy Url"),
         Description("A url to the web proxy that will handle connections between the javascript code and the completion server.")]
        public string AutoCompleteWebProxyPage
        {
            get { return autoCompleteWebProxyPage; }
            set { autoCompleteWebProxyPage = value; }
        }

        #endregion

        /// <summary>
        /// Default Constructor which disbled the Scope Drop Downs from the search box
        /// </summary>
        public ESPAutoCompleteSearchBox()
        {
            DropDownModeEx = DropDownModesEx.HideScopeDD;
            DropDownMode = DropDownModes.HideDD_NoScope;

            PreRender += new EventHandler(ESPAutoCompleteSearchBox_PreRender);
        }

        void ESPAutoCompleteSearchBox_PreRender(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(JavaScriptFiles))
            {
                string[] javaScriptFilenames = JavaScriptFiles.Split(new char[] { ',' });
                foreach (string filename in javaScriptFilenames)
                {
                    if (!String.IsNullOrEmpty(filename))
                    {
                        string fileIncludeScriptKey = filename + "IncludeScript";

                        if (!Page.ClientScript.IsClientScriptBlockRegistered(GetType(), fileIncludeScriptKey))
                        {
                            //String dirLocation = this.ClassResourcePath + "/";
                            String dirLocation = autocompleteScriptDirLocation;

                            // Create the client script block.
                            string includeScriptBlock = String.Format(IncludeScriptFormat, "javascript", dirLocation, filename);
                            Page.ClientScript.RegisterClientScriptBlock(GetType(), fileIncludeScriptKey, includeScriptBlock);
                        }
                    }

                }
            }


            HtmlLink cssLink = new HtmlLink();
            cssLink.Attributes.Add("type", "text/css");
            cssLink.Attributes.Add("rel", "stylesheet");
            cssLink.Attributes.Add("href", "/_layouts/autocompleteproxy/autocomplete.css");
            Page.Header.Controls.Add(cssLink);

        }

        #region Disabled properties
        /// <summary>
        /// Disable the DropDownModesEx property to not be able to configure it in the web part editor 
        /// </summary>
        [Browsable(false), Resources("SearchBox_DDMode", "SearchBox_ScopeDD", "SearchBox_DDMode_ToolTip"), WebPartStorage(Storage.Shared)]
        public new DropDownModesEx DropDownModeEx
        {
            get
            {
                return base.DropDownModeEx;
            }
            set
            {
                base.DropDownModeEx = value;
            }
        }

        /// <summary>
        /// Disable the DropDownModes property to not be able to configure it in the web part editor 
        /// </summary>
        [Browsable(false), Resources("SearchBox_DDMode", "SearchBox_ScopeDD", "SearchBox_DDMode_ToolTip"), WebPartStorage(Storage.None)]
        public new DropDownModes DropDownMode
        {
            get
            {
                return base.DropDownMode; // DropDownModes.HideDD_NoScope;
            }
            set
            {
                base.DropDownMode = value;
            }
        }

        /// <summary>
        /// Disable the DropDownWidth property to not be able to configure it in the web part editor 
        /// </summary>
        [Browsable(false), Resources("SearchBox_DDWidth", "SearchBox_ScopeDD", "SearchBox_DDWidth_ToolTip"), DefaultValue(0), WebPartStorage(Storage.Shared)]
        public new int DropDownWidth
        {
            get
            {
                return base.DropDownWidth;
            }
            set
            {
                base.DropDownWidth = value;
            }
        }

        /// <summary>
        /// Disable the TextBeforeDropDown property to not be able to configure it in the web part editor 
        /// </summary>
        [Browsable(false), Resources("SearchBox_DDLabel", "SearchBox_ScopeDD", "SearchBox_DDLabel_ToolTip"), DefaultValue(""), WebPartStorage(Storage.Shared)]
        public new string TextBeforeDropDown
        {
            get
            { return base.TextBeforeDropDown; }
            set
            {
                base.TextBeforeDropDown = value;
            }
        }

        /// <summary>
        /// Disable the ScopeDisplayGroupName property to not be able to configure it in the web part editor 
        /// </summary>
        [Browsable(false), Resources("SearchBox_ScopeDisplayGroup", "", "SearchBox_ScopeDisplayGroup_ToolTip"), WebPartStorage(Storage.Shared)]
        public new string ScopeDisplayGroupName
        {
            get
            {
                return base.ScopeDisplayGroupName;
            }
            set
            {
                base.ScopeDisplayGroupName = value;
            }
        }

        /// <summary>
        /// Disable the AdvancedSearchPageURL property to not be able to configure it in the web part editor 
        /// </summary>
        [Browsable(false), WebPartStorage(Storage.Shared), Resources("SearchBox_AdvancedSearchURL", "", "SearchBox_AdvancedSearchURL_ToolTip")]
        public new string AdvancedSearchPageURL
        {
            get
            {
                return base.AdvancedSearchPageURL;
            }
            set
            {
                base.AdvancedSearchPageURL = value;
            }
        }

        /// <summary>
        /// Disable the ShowAdvancedSearch property to not be able to configure it in the web part editor 
        /// </summary>
        [Browsable(false), Resources("SearchBox_DisplayAdvSearchLink", "", "SearchBox_DisplayAdvSearchLink_ToolTip"), WebPartStorage(Storage.Shared), DefaultValue(false)]
        public new bool ShowAdvancedSearch
        {
            get
            {
                return base.ShowAdvancedSearch;
            }
            set
            {
                base.ShowAdvancedSearch = value;
            }
        }

        #endregion

        private Panel GenerateAutoCompleteDisplayPanel()
        {
            Panel autoCompleteDiv = new Panel();
            autoCompleteDiv.ID = "autocomplete";
            autoCompleteDiv.CssClass = "autocomplete";

            return autoCompleteDiv;
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            string formClientId = "",
                   inputBoxClientId = "",
                   autoCompleteDisplayClientId = "";

            // get the main form client id
            if (Page != null && Page.Form != null)
                formClientId = Page.Form.ClientID;


            // set the div element that will hold the suggestions on the page
            Panel autoCompleteDisplay = GenerateAutoCompleteDisplayPanel();

            // Add the div tag to the start of the web page.
            // The recommended way is to use absolute position 
            // the div tag according to the whole page. 
            // This should be performed in the javascript code.
            this.Controls.AddAt(0, autoCompleteDisplay);


            // get the client id of the autocomplete display element
            if (autoCompleteDisplay != null)
                autoCompleteDisplayClientId = autoCompleteDisplay.ClientID;


            // get the search input text box and its client id
            TextBox inputTextBox = GetInputTextBox();
            if (inputTextBox != null)
            {
                inputTextBox.Attributes.Add("autocomplete", "off");
                inputBoxClientId = inputTextBox.ClientID;
            }


            // set the autocomplete embedded script format
            if (!String.IsNullOrEmpty(AutoCompleteEmbeddedScriptFormat))
            {
                string autoCompleteEmbeddedScript = AutoCompleteEmbeddedScriptFormat.Replace("{PROXY}", AutoCompleteWebProxyPage);
                autoCompleteEmbeddedScript = autoCompleteEmbeddedScript.Replace("{FORM_ID}", formClientId);
                autoCompleteEmbeddedScript = autoCompleteEmbeddedScript.Replace("{AUTOCOMPLETE_DIV_CLIENT_ID}", autoCompleteDisplayClientId);
                autoCompleteEmbeddedScript = autoCompleteEmbeddedScript.Replace("{INPUTBOX_ID}", inputBoxClientId);

                // Check to see if the startup script is already registered.
                if (!Page.ClientScript.IsStartupScriptRegistered(GetType(), AutoCompleteIncludeScriptKey))
                {
                    Page.ClientScript.RegisterStartupScript(GetType(), AutoCompleteIncludeScriptKey, autoCompleteEmbeddedScript, false);
                }
            }
        }

        private TextBox GetInputTextBox()
        {
            foreach (Control control in Controls)
            {
                if (control is Table)
                {
                    Table table = control as Table;
                    foreach (TableRow row in table.Rows)
                    {
                        foreach (TableCell cell in row.Cells)
                        {
                            if (cell.Controls != null && cell.Controls.Count > 0)
                            {
                                foreach (Control c in cell.Controls)
                                {
                                    if (c is TextBox)
                                    {
                                        return c as TextBox;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// Set the WebPart to initially no use a frame aroud it.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            ChromeType = PartChromeType.None;
        }

        /// <inheritdoc/>
        [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        protected override void OnPreRender(object sender, EventArgs e)
        {
            if (SearchResultPageURL != null && SearchResultPageURL.EndsWith("OSSSearchResults.aspx"))
            {
                SearchResultPageURL = Page.Request.Url.LocalPath;
            }

            base.OnPreRender(sender, e);
        }
    }
}
